"""This module contains common functions used when constructing or manipulating
strings.
""" 

"""Project Euler Solutions Library

Copyright (c) 2011 by Robert Vella - robert.r.h.vella@gmail.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""



from euler.numbers.decimal_base import integer_to_digits

#An array mapping the words for all the numbers from 0 to 19, to their 
#respective number.
__TEEN_DIGIT_WORD_MAP = [None,
                     "one",
                     "two",
                     "three",
                     "four",
                     "five",
                     "six",
                     "seven",
                     "eight",
                     "nine",
                     "ten",
                     "eleven",
                     "twelve",
                     "thirteen",
                     "fourteen",
                     "fifteen",
                     "sixteen",
                     "seventeen",
                     "eighteen",
                     "nineteen"                     
                     ]    

#An array mapping the words for all the multiples of 10 from 0 to 90, to their
#first digit.
__TEN_MULTIPLE_WORD_MAP = [None,
                        None,
                        "twenty",
                        "thirty",
                        "forty",
                        "fifty",
                        "sixty",
                        "seventy",
                        "eighty",
                        "ninety"
                        ]    

#An array mapping the words for all the exponents of 10 from 0 to 1000, to the
#location of their first digit within a number.
__DIGIT_LOCATION_WORD_MAP = [None,
                           None,
                           "hundred",
                           "thousand"]

def number_to_sentence(integer):
    """Returns the number, [integer], in the form of a sentence.
    
    Example:
        integer = 12: twelve
        integer = 523: five hundred and twenty three
    
    Note:
        Currently, this function only evaluates numbers up to four digits long.
    """
    
    #The list of digits within [integer], reversed.
    digitlist = list(integer_to_digits(integer))
    digitlist.reverse()    
    
    #The sentence expressing [integer].
    sentence = ""       
    
    #For each digit location within digitlist, with 0 begin the first digit
    #and 3 being 1000.
    for current_location in range(len(digitlist) - 1, -1, -1):
        #If the current location is within the hundreds or thousands, add
        #the number at this location and the quantity describing its location
        #(one hundred... two thousand ... five thousand).
        if current_location > 1:
            number_at_location = digitlist[current_location]
            
            if number_at_location != 0:
                sentence += __TEEN_DIGIT_WORD_MAP[number_at_location] + " " 
                sentence += __DIGIT_LOCATION_WORD_MAP[current_location] + " "
         
        #Otherwise, if there is a number present in the last two digits.   
        elif digitlist[0] != 0 or digitlist[1] != 0:
            #If there are any hundreds or thousands present in the number,
            #add "and" to the sentence.
            if(integer > 99):
                sentence += "and "
            
            #The number at the current digit location. Either the first
            #or the second, if it exists.
            number_at_location = digitlist[current_location]
            
            #If this is the second digit, and if that digits is greater than
            #1, then add the last two digits to the sentence in their two
            #word form: twenty one, thirty four, twenty one.
            if current_location == 1 and number_at_location > 1:
                number_at_previous_location = digitlist[current_location - 1]
                
                sentence += __TEN_MULTIPLE_WORD_MAP[number_at_location]
                
                if number_at_previous_location != 0:
                    sentence += " " \
                        + __TEEN_DIGIT_WORD_MAP[number_at_previous_location]
            
            #Otherwise, consider the last two digits as one number and 
            #add them to the sentence as one word: eleven, one, two, 
            #thirteen, four.
            else:
                number_to_evaluate = number_at_location
                
                if current_location == 1:
                    number_to_evaluate *= 10
                    number_to_evaluate += digitlist[current_location - 1]
                 
                sentence += __TEEN_DIGIT_WORD_MAP[number_to_evaluate]
                
                  
            #Once the last two digits have been processed, stop looping.
            break
            
    #Return the sentence.
    return sentence

def alphabetical_value(string):
    """Returns the alphabetic value for [string]. i.e. The sum of the position
    of each of [string]'s characters within the alphabet.
    """
    
    return sum(map(lambda x : ord(x.lower()) - 96, string))  

